#include "bmp280.h"

// &spi0 {
// 	status = "okay";
// 	bmp280:bmp280@58{
// 		compatible = "bmp280";
// 		cs-gpio = "PC2";
// 		reg = <0x76>;
// 	}
// };

static struct bmp280_driver_class bmp280_dev;
BMP280_S32_t t_fine;
uint16_t    Dig_T1;
int16_t     Dig_T2;
int16_t     Dig_T3;
uint16_t    Dig_P1;
int16_t     Dig_P2;
int16_t     Dig_P3;
int16_t     Dig_P4;
int16_t     Dig_P5;
int16_t     Dig_P6;
int16_t     Dig_P7;
int16_t     Dig_P8;
int16_t     Dig_P9;

/**
  * 函    数：读取寄存器
  * 参    数：首个读取的寄存器地址以及读取返回数组和读取长度
  * 返 回 值：none
  */
int BMP280_ReadData(uint8_t addr, uint8_t *readData, uint8_t len)
{
    struct spi_message msg;
    struct spi_transfer xfer[2] = {0};

    /* 发送命令 */
    addr |= 0x80;
    xfer[0].tx_buf = &addr; // 读高位必须为1
    xfer[0].len = 1;
    xfer[0].cs_change = 1;

    /* 读取数据 */
    xfer[1].rx_buf = readData;
    xfer[1].len = len;
    xfer[1].cs_change = 1;

    spi_message_init(&msg);
    spi_message_add_tail(&xfer[0], &msg);
    spi_message_add_tail(&xfer[1], &msg);

    return spi_sync(bmp280_dev.spix, &msg);
}

/**
  * 函    数：写入单个寄存器
  * 参    数：要写入的寄存器地址以及写入参数
  * 返 回 值：none
  */
int BMP280_WriteData(uint8_t addr, uint8_t data)
{
    struct spi_message msg;
    struct spi_transfer xfer[2] = {0};

    /* 发送命令 */
    xfer[0].tx_buf = &addr;
    xfer[0].len = 1;
    xfer[0].cs_change = 1;

    /* 读取数据 */
    xfer[1].rx_buf = NULL;
    xfer[1].len = 1;
    xfer[1].cs_change = 1;

    spi_message_init(&msg);
    spi_message_add_tail(&xfer[0], &msg);
    spi_message_add_tail(&xfer[1], &msg);

    return spi_sync(bmp280_dev.spix, &msg);
}

/**
  * 函    数：读取转换3个连续寄存器
  * 参    数：首个读取的寄存器
  * 返 回 值：合并后的总值
  */
long BMP280_RegReadThree(unsigned char addr)
{
    unsigned char ArrayReadThree[3];               //定义要读取数据的测试数组
    long temp = 0;
    BMP280_ReadData(addr, ArrayReadThree, 3);

    temp = (long)(((unsigned long)ArrayReadThree[0] << 12)|((unsigned long)ArrayReadThree[1] << 4)|((unsigned long)ArrayReadThree[2] >> 4));

    return temp;
}
/**
  * 函    数：读取转换2个连续寄存器
  * 参    数：首个读取的寄存器
  * 返 回 值：合并后的总值
  */
short BMP280_RegReadTwo(unsigned char addr)
{
    unsigned char ArrayReadTwo[2];               //定义要读取数据的测试数组
    short temp = 0;
    BMP280_ReadData(addr, ArrayReadTwo, 2);   //ArrayRead[0]:LSB ArrayRead[1]:MSB 

    temp = (short)ArrayReadTwo[1] << 8;
    temp |= (short)ArrayReadTwo[0];

    return temp;
}
/**
  * 函    数：BMP280获取温度值
  * 参    数：无
  * 返 回 值：温度值
  */
int32_t BMP280_GetTemp(void)
{
    BMP280_S32_t var1, var2, T;
    BMP280_S32_t adc_T;
    adc_T = BMP280_RegReadThree(BMP280_TEMPERATURE_MSB_REG);
    var1 = ((((adc_T >> 3) - ((BMP280_S32_t)Dig_T1 << 1))) * ((BMP280_S32_t)Dig_T2)) >> 11;
    var2 = (((((adc_T >> 4) - ((BMP280_S32_t)Dig_T1)) * ((adc_T >> 4) - ((BMP280_S32_t)Dig_T1))) >> 12) * 
    ((BMP280_S32_t)Dig_T3)) >> 14;
    t_fine = var1 + var2;
    T = (t_fine * 5 + 128) >> 8;
    return T;
}

/**
  * 函    数：BMP280获取压力值
  * 参    数：无
  * 返 回 值：压力值
  */
uint32_t BMP280_GetPress(void)
{
    BMP280_S64_t var1, var2, p;
    BMP280_S32_t adc_P;
    adc_P = BMP280_RegReadThree(BMP280_PRESSURE_MSB_REG);
    var1 = ((BMP280_S64_t)t_fine) - 128000;
    var2 = var1 * var1 * (BMP280_S64_t)Dig_P6;
    var2 = var2 + ((var1 * (BMP280_S64_t)Dig_P5) << 17);
    var2 = var2 + (((BMP280_S64_t)Dig_P4) << 35);
    var1 = ((var1 * var1 * (BMP280_S64_t)Dig_P3) >> 8) + ((var1 * (BMP280_S64_t)Dig_P2) << 12);
    var1 = (((((BMP280_S64_t)1) << 47) + var1)) * ((BMP280_S64_t)Dig_P1) >> 33;
    if (var1 == 0)
    {
    return 0; // avoid exception caused by division by zero
    }
    p = 1048576 - adc_P;
    p = (((p<<31) - var2) * 3125) / var1;
    var1 = (((BMP280_S64_t)Dig_P9) * (p>>13) * (p>>13)) >> 25;
    var2 = (((BMP280_S64_t)Dig_P8) * p) >> 19;
    p = ((p + var1 + var2) >> 8) + (((BMP280_S64_t)Dig_P7) << 4);
    return (BMP280_U32_t)p;

}

/*
 * @description    : 读取bmp280的数据，读取原始数据， 注意！ 
 * @return         : 无。
 */
void bmp280_readdata(struct bmp280_driver_class *dev)
{
    dev->press = BMP280_GetPress();
    dev->temp = BMP280_GetTemp();
}

/*
 * @description        : 打开设备
 * @param - inode     : 传递给驱动的inode
 * @param - filp     : 设备文件，file结构体有个叫做private_data的成员变量
 *                       一般在open的时候将private_data指向设备结构体。
 * @return             : 0 成功;其他 失败
 */
static int bmp280_open(struct inode *inode, struct file *filp)
{
    /* 初始化bmp280 */
    uint8_t Osrs_T = 1;             //Temperature oversampling x 1
    uint8_t Osrs_P = 3;             //Pressure oversampling x 1
    uint8_t Mode = 3;               //Normal mode
    uint8_t T_sb = 5;               //Tstandby 1000ms
    uint8_t Filter = 4;             // 滤波等级  
    uint8_t Spi3w_en = 0;           // 三线SPI模式
    
    uint8_t Ctrl_meas_reg = (Osrs_T << 5) | (Osrs_P << 2) | Mode;
    uint8_t Config_reg    = (T_sb << 5) | (Filter << 2) | Spi3w_en;
    
    filp->private_data = &bmp280_dev; // 文件

    //状态全部清零
    BMP280_WriteData(BMP280_RESET_REG, BMP280_RESET_VALUE);
    BMP280_WriteData(BMP280_CTRLMEAS_REG, Ctrl_meas_reg);
    BMP280_WriteData(BMP280_CONFIG_REG, Config_reg);
    msleep(20);
    
    Dig_T1 = BMP280_RegReadTwo(BMP280_DIG_T1_LSB_REG);
    Dig_T2 = BMP280_RegReadTwo(BMP280_DIG_T2_LSB_REG);
    Dig_T3 = BMP280_RegReadTwo(BMP280_DIG_T3_LSB_REG);
    Dig_P1 = BMP280_RegReadTwo(BMP280_DIG_P1_LSB_REG);
    Dig_P2 = BMP280_RegReadTwo(BMP280_DIG_P2_LSB_REG);
    Dig_P3 = BMP280_RegReadTwo(BMP280_DIG_P3_LSB_REG);
    Dig_P4 = BMP280_RegReadTwo(BMP280_DIG_P4_LSB_REG);
    Dig_P5 = BMP280_RegReadTwo(BMP280_DIG_P5_LSB_REG);
    Dig_P6 = BMP280_RegReadTwo(BMP280_DIG_P6_LSB_REG);
    Dig_P7 = BMP280_RegReadTwo(BMP280_DIG_P7_LSB_REG);
    Dig_P8 = BMP280_RegReadTwo(BMP280_DIG_P8_LSB_REG);
    Dig_P9 = BMP280_RegReadTwo(BMP280_DIG_P9_LSB_REG);

    return 0;
}
 
/*
 * @description        : 从设备读取数据 
 * @param - filp     : 要打开的设备文件(文件描述符)
 * @param - buf     : 返回给用户空间的数据缓冲区
 * @param - cnt     : 要读取的数据长度
 * @param - offt     : 相对于文件首地址的偏移
 * @return             : 读取的字节数，如果为负值，表示读取失败
*/
static ssize_t bmp280_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{
    float data[2];
    long err = 0;
 
    struct bmp280_driver_class *dev = (struct bmp280_driver_class *)filp->private_data;
    bmp280_readdata(dev);

    data[0] = dev->press;
    data[1] = dev->temp;
    
    err = copy_to_user(buf, data, sizeof(data));
    return 0;
}
 

 
/* bmp280操作函数 */
static const struct file_operations bmp280_ops = {
    .owner = THIS_MODULE,
    .open = bmp280_open,
    .read = bmp280_read,
};

static int bmp280_probe(struct spi_device *spi)
{

    bmp280_dev.spix = spi;

    /* 1、构建设备号 */
    if (bmp280_dev.major_num) {
        bmp280_dev.dev_num = MKDEV(bmp280_dev.major_num, 0);
        register_chrdev_region(bmp280_dev.dev_num, DEVICE_NUMBER, CHARDEV_NAME);
    } else {
        alloc_chrdev_region(&bmp280_dev.dev_num, 0, DEVICE_NUMBER, CHARDEV_NAME);
        bmp280_dev.major_num = MAJOR(bmp280_dev.dev_num);
    }
 
    /* 2、注册设备 */
    cdev_init(&bmp280_dev.cdev, &bmp280_ops);
    cdev_add(&bmp280_dev.cdev, bmp280_dev.dev_num, DEVICE_NUMBER);
 
    /* 3、创建类 */
    bmp280_dev.class = class_create(THIS_MODULE, DEVICE_CLASS_NAME);
    if (IS_ERR(bmp280_dev.class)) {
        return PTR_ERR(bmp280_dev.class);
    }

    /* 4、创建设备 */
    bmp280_dev.device = device_create(bmp280_dev.class, NULL, bmp280_dev.dev_num, NULL, DEVICE_NODE_NAME); // 默认使用
    if (IS_ERR(bmp280_dev.device)) {
        return PTR_ERR(bmp280_dev.device);
    }

    bmp280_dev.spix = spi;

    return 0;
}

static int bmp280_remove(struct spi_device *spi)
{
    return 0;
}


/* 传统匹配方式ID列表 */
const struct spi_device_id bmp280_id_table [] = {
    {ID_TABLE_COMPATILBLE, 0 },
	{}
};

/* 设备树匹配列表 */
const struct of_device_id  bmp280_of_match_table[] = {
    {.compatible = OF_MATCH_COMPATILBLE},
	{}
};

/* spi驱动结构体 */
struct spi_driver spi_bmp280 = {
    .probe = bmp280_probe,
    .remove = bmp280_remove,
    .driver = {
        .name = "bmp280",
        .owner = THIS_MODULE,
        .of_match_table = bmp280_of_match_table
    },
    .id_table = bmp280_id_table
};

static int __init bmp280_init(void)
{
    int ret = 0;
    ret = spi_register_driver(&spi_bmp280);
    if(ret < 0)
    {
        printk("spi_register_driver spi_bmp280 faild!\n");
    }
    return ret;
}
static void __exit bmp280_exit(void)
{
    spi_unregister_driver(&spi_bmp280);
    printk("spi_unregister_driver spi_bmp280\n");
}

module_init(bmp280_init);
module_exit(bmp280_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("kongjun");

 
 
 